use crate::{geometry::Coord, level::Level};

pub struct Block {
    pub pos: Coord,
    pub level: Level,
    state: State,
}

enum State {
    New,
    Old { to: Coord, will_remove: bool },
}

impl Block {
    pub fn new(pos: Coord, level: Level) -> Self {
        let state = State::New;
        Self { pos, level, state }
    }

    pub fn dst(&self) -> Option<Coord> {
        match self.state {
            State::Old { to, .. } => Some(to),
            State::New => None,
        }
    }

    pub fn is_new(&self) -> bool {
        matches!(self.state, State::New)
    }

    pub fn will_remove(&self) -> bool {
        match self.state {
            State::Old { will_remove, .. } => will_remove,
            State::New => false,
        }
    }

    pub fn run(&mut self) {
        match self.state {
            State::New => {
                self.state = State::Old {
                    to: self.pos,
                    will_remove: false,
                };
            }
            State::Old { to, .. } => {
                self.pos = to;
            }
        }
    }

    pub fn to(&mut self, dst: Coord) {
        debug_assert!(!self.is_new(), "新的块不能移动"); // 由于不影响安全，只需debug
        self.state = State::Old {
            to: dst,
            will_remove: false,
        };
    }

    pub fn eliminate(&mut self) {
        self.state = State::Old {
            to: self.dst().expect("新的块不能消除"),
            will_remove: true,
        };
    }
}
